<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>教室座位表管理系统</title>
    <!-- 引入Tailwind CSS -->
    <script src="https://cdn.tailwindcss.com"></script>
    <!-- 引入Font Awesome -->
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <!-- 后端 API 辅助方法 -->
    <script>
        let CURRENT_CLASSROOM_ID = null;
        const API = {
            classes: '/api/classes',
            classrooms: '/api/classrooms',
            seatConfigActive: (classroomId) => `/api/seat-config/active/${classroomId}`,
            seatConfig: '/api/seat-config',
            seatsByClassroom: (classroomId) => `/api/seats/classroom/${classroomId}`,
            seats: '/api/seats'
        };

        const apiGet = async (url) => fetch(url, {credentials: 'same-origin'}).then(r => r.json());
        const apiJson = async (url, method, body) => fetch(url, {
            method,
            headers: {'Content-Type': 'application/json'},
            credentials: 'same-origin',
            body: body ? JSON.stringify(body) : undefined
        }).then(async r => {
            if (r.ok) {
                try {
                    return await r.json();
                } catch {
                    return true;
                }
            }
            const text = await r.text();
            throw new Error(text || r.statusText);
        });
    </script>

    <!-- 配置Tailwind自定义颜色和字体 -->
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3B82F6',
                        secondary: '#6366F1',
                        accent: '#10B981',
                        neutral: '#64748B',
                        light: '#F8FAFC',
                        dark: '#1E293B'
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif'],
                    },
                },
            }
        }
    </script>

    <!-- 自定义工具类 -->
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }

            .seat-hover {
                @apply transition-all duration-300 hover:shadow-lg hover:-translate-y-1;
            }

            .section-divider {
                @apply w-1 bg-gray-300 mx-2 hidden md:block;
            }

            .class-badge {
                @apply w-3 h-3 rounded-full inline-block mr-1;
            }

            .notification {
                @apply fixed top-4 right-4 p-4 rounded-lg shadow-lg z-50 transform transition-all duration-300 translate-x-full opacity-0;
            }

            .notification.show {
                @apply translate-x-0 opacity-100;
            }

            .color-picker {
                @apply w-8 h-8 rounded-full cursor-pointer border-2 border-white shadow-sm transition-transform hover:scale-110;
            }

            .file-drop-area {
                @apply border-2 border-dashed border-gray-300 rounded-lg p-6 text-center cursor-pointer transition-colors hover:border-primary hover:bg-blue-50;
            }
        }
    </style>
    <style>
        :root {
            --seat-size: 112px;
        }

        .seat-tile {
            width: var(--seat-size);
            height: var(--seat-size);
        }

        .aisle {
            width: 12px;
            background-color: #e5e7eb; /* gray-200 */
            border-radius: 4px;
            margin: 0 8px;
            align-self: stretch; /* 在flex容器内纵向拉伸 */
            min-height: 100%;
            flex: 0 0 12px; /* 防止被压缩为0，始终占位 */
            position: relative;
            z-index: 2; /* 保证显示在座位之上 */
            pointer-events: none; /* 不遮挡点击 */
        }

        @media (max-width: 1280px) {
            .aisle {
                width: 8px;
            }
        }

        @media (max-width: 768px) {
            .aisle {
                width: 6px;
            }
        }

        body { overflow-x: hidden; }

        /* 三个区域容器不参与伸缩，避免覆盖走道 */
        #seating-container { align-items: stretch; }
        #left-section, #middle-section, #right-section { flex: 0 0 auto; }

        /* 为整体座位区域增加左右留白，随屏幕宽度自适应 */
        #seating-container { padding-left: 24px; padding-right: 24px; }
        @media (max-width: 1280px) { #seating-container { padding-left: 16px; padding-right: 16px; } }
        @media (max-width: 768px)  { #seating-container { padding-left: 12px; padding-right: 12px; } }
    </style>
</head>
<body class="bg-gray-50 min-h-screen font-sans">
<!-- 顶部导航栏 -->
<header class="bg-white shadow-md sticky top-0 z-50">
    <div class="container mx-auto px-4 py-4 flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
        <div class="flex items-center space-x-2 w-full md:w-auto">
            <i class="fa fa-graduation-cap text-primary text-2xl"></i>
            <h1 class="text-xl md:text-2xl font-bold text-dark">教室座位表管理系统</h1>
        </div>
        <div class="flex flex-wrap items-center gap-3 w-full md:w-auto justify-between md:justify-end">
            <div class="flex items-center flex-wrap gap-3 text-sm" id="class-legend">
                <!-- 班级图例将通过JS生成 -->
            </div>
            <div class="flex items-center space-x-3">
                <div class="hidden md:flex items-center space-x-1 text-neutral">
                    <i class="fa fa-users"></i>
                    <span id="total-count">总人数: 0</span>
                </div>

                <button id="class-config-btn"
                        class="bg-purple-500 hover:bg-purple-600 text-white px-4 py-2 rounded-lg transition-colors">
                    <i class="fa fa-sitemap mr-1"></i>班级管理
                </button>

                <button id="config-btn"
                        class="bg-secondary hover:bg-secondary/90 text-white px-4 py-2 rounded-lg transition-colors">
                    <i class="fa fa-cog mr-1"></i>座位配置
                </button>
            </div>
        </div>
    </div>
</header>

<!-- 主内容区 -->
<main class="container mx-auto px-4 py-6">
    <!-- 信息面板 -->
    <div class="bg-white rounded-xl shadow-sm p-4 mb-6">
        <div class="flex flex-col md:flex-row justify-between items-start md:items-center">
            <div>
                <h2 class="text-lg font-semibold text-dark">课程: 工程数学</h2>
                <p class="text-neutral text-sm mt-1">教室: 躬行楼B1-401 </p>
            </div>
            <div class="mt-3 md:mt-0 flex space-x-2">
                <div class="flex items-center text-sm">
                    <span class="w-3 h-3 bg-blue-100 border border-blue-500 rounded-sm inline-block mr-1"></span>
                    <span>已分配</span>
                </div>
                <div class="flex items-center text-sm">
                    <span class="w-3 h-3 bg-gray-100 border border-gray-300 rounded-sm inline-block mr-1"></span>
                    <span>未分配</span>
                </div>
            </div>
        </div>
    </div>

    <!-- 讲台区域 -->
    <div class="flex justify-center mb-8">
        <div class="w-full max-w-md h-16 bg-gray-200 rounded-lg flex items-center justify-center border-2 border-gray-300 shadow-sm">
            <p class="text-gray-700 font-medium">讲台</p>
        </div>
    </div>

    <!-- 座位区域 -->
    <div class="pb-4">
        <div id="seating-container" class="flex w-full justify-center">
            <!-- 左侧区域 -->
            <div id="left-section" class="flex space-x-2">
                <!-- 左侧座位将通过JavaScript生成 -->
            </div>

            <!-- 中间分隔线 -->
            <div class="aisle"></div>

            <!-- 中间区域 -->
            <div id="middle-section" class="flex space-x-2">
                <!-- 中间座位将通过JavaScript生成 -->
            </div>

            <!-- 中间分隔线 -->
            <div class="aisle"></div>

            <!-- 右侧区域 -->
            <div id="right-section" class="flex space-x-2">
                <!-- 右侧座位将通过JavaScript生成 -->
            </div>
        </div>
    </div>
</main>

<!-- 页脚 -->
<!-- 离线工作提示 -->
<div id="offline-notice"
     class="hidden fixed bottom-4 right-4 bg-red-50 border-l-4 border-red-400 p-3 rounded-r shadow-md max-w-xs z-40">
    <div class="flex items-center">
        <i class="fa fa-warning text-red-500 mr-2"></i>
        <p class="text-xs text-red-700">当前离线，数据可能无法同步</p>
    </div>
</div>

<footer class="bg-white border-t border-gray-200 py-4 mt-8">
    <div class="container mx-auto px-4 text-center text-neutral text-sm">
        <p>© 2023 学校管理系统 - 教室座位表 | 数据存储在后端数据库</p>
    </div>
</footer>

<!-- 配置弹窗 -->
<div id="config-modal" class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center hidden">
    <div class="bg-white rounded-xl shadow-lg w-full max-w-md p-6 transform transition-all">
        <div class="flex justify-between items-center mb-4">
            <h3 class="text-lg font-bold text-dark">座位配置</h3>
            <button id="close-config" class="text-gray-500 hover:text-gray-700">
                <i class="fa fa-times"></i>
            </button>
        </div>

        <div class="space-y-4">
            <div>
                <label class="block text-sm font-medium text-gray-700 mb-1">左侧区域</label>
                <div class="flex space-x-2">
                    <div class="flex-1">
                        <label class="block text-xs text-gray-500 mb-1">列数</label>
                        <input type="number" id="left-columns" min="1" max="10"
                               class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm" value="4">
                    </div>
                    <div class="flex-1">
                        <label class="block text-xs text-gray-500 mb-1">行数</label>
                        <input type="number" id="left-rows" min="1" max="20"
                               class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm" value="9">
                    </div>
                </div>
            </div>

            <div>
                <label class="block text-sm font-medium text-gray-700 mb-1">中间区域</label>
                <div class="flex space-x-2">
                    <div class="flex-1">
                        <label class="block text-xs text-gray-500 mb-1">列数</label>
                        <input type="number" id="middle-columns" min="1" max="10"
                               class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm" value="6">
                    </div>
                    <div class="flex-1">
                        <label class="block text-xs text-gray-500 mb-1">行数</label>
                        <input type="number" id="middle-rows" min="1" max="20"
                               class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm" value="10">
                    </div>
                </div>
            </div>

            <div>
                <label class="block text-sm font-medium text-gray-700 mb-1">右侧区域</label>
                <div class="flex space-x-2">
                    <div class="flex-1">
                        <label class="block text-xs text-gray-500 mb-1">列数</label>
                        <input type="number" id="right-columns" min="1" max="10"
                               class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm" value="4">
                    </div>
                    <div class="flex-1">
                        <label class="block text-xs text-gray-500 mb-1">行数</label>
                        <input type="number" id="right-rows" min="1" max="20"
                               class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm" value="6">
                    </div>
                </div>
            </div>

            <div class="pt-2">
                <button id="apply-config"
                        class="w-full bg-primary hover:bg-primary/90 text-white py-2 rounded-lg transition-colors">
                    应用配置
                </button>
            </div>
        </div>
    </div>
</div>

<!-- 班级配置弹窗 -->
<div id="class-config-modal" class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center hidden">
    <div class="bg-white rounded-xl shadow-lg w-full max-w-2xl p-6 transform transition-all max-h-[90vh] overflow-y-auto">
        <div class="flex justify-between items-center mb-6">
            <h3 class="text-lg font-bold text-dark">班级管理</h3>
            <button id="close-class-config" class="text-gray-500 hover:text-gray-700">
                <i class="fa fa-times"></i>
            </button>
        </div>

        <div class="mb-6">
            <p class="text-sm text-neutral mb-4">在这里可以修改班级名称和对应的颜色标识，修改后将立即应用到座位表中。</p>

            <div id="classes-container" class="space-y-4">
                <!-- 班级配置项将通过JS生成 -->
            </div>

            <div class="mt-6 flex justify-between">
                <button id="add-class"
                        class="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-lg transition-colors">
                    <i class="fa fa-plus mr-1"></i>添加班级
                </button>
                <button id="reset-classes"
                        class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-4 py-2 rounded-lg transition-colors">
                    <i class="fa fa-refresh mr-1"></i>恢复默认
                </button>
            </div>
        </div>
    </div>
</div>

<!-- 导入弹窗 -->
<div id="import-modal" class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center hidden">
    <div class="bg-white rounded-xl shadow-lg w-full max-w-2xl p-6 transform transition-all">
        <div class="flex justify-between items-center mb-6">
            <h3 class="text-lg font-bold text-dark">导入座位信息</h3>
            <button id="close-import" class="text-gray-500 hover:text-gray-700">
                <i class="fa fa-times"></i>
            </button>
        </div>

        <div class="mb-6">
            <p class="text-sm text-neutral mb-4">上传JSON格式的文件导入座位信息，支持按位置或自动分配方式导入。</p>

            <div id="file-drop-area" class="file-drop-area mb-6">
                <input type="file" id="import-file" accept=".json" class="hidden">
                <div class="flex flex-col items-center justify-center">
                    <i class="fa fa-cloud-upload text-3xl text-gray-400 mb-2"></i>
                    <p class="text-sm text-gray-500">点击或拖拽JSON文件到此处</p>
                    <p class="text-xs text-gray-400 mt-1">支持的格式：.json</p>
                </div>
            </div>

            <div class="mb-4">
                <label class="block text-sm font-medium text-gray-700 mb-2">导入方式</label>
                <div class="space-y-2">
                    <div class="flex items-center">
                        <input type="radio" id="import-by-position" name="import-method" value="position" class="mr-2"
                               checked>
                        <label for="import-by-position" class="text-sm">按座位位置导入（匹配列数-行数）</label>
                    </div>
                    <div class="flex items-center">
                        <input type="radio" id="import-auto" name="import-method" value="auto" class="mr-2">
                        <label for="import-auto" class="text-sm">自动分配（按顺序填充未分配座位）</label>
                    </div>
                    <div class="flex items-center">
                        <input type="checkbox" id="overwrite-existing" class="mr-2">
                        <label for="overwrite-existing" class="text-sm">覆盖已存在的座位信息</label>
                    </div>
                </div>
            </div>

            <div class="bg-blue-50 p-4 rounded-lg mb-4">
                <h4 class="font-medium text-sm text-blue-800 mb-2">JSON格式示例</h4>
                <pre class="text-xs bg-white p-2 rounded overflow-x-auto text-gray-700">{
  "1列-1行": {
    "id": "2023001001",
    "name": "张三",
    "phone": "13800138000",
    "class": "1"
  },
  "1列-2行": {
    "id": "2023001002",
    "name": "李四",
    "phone": "13900139000",
    "class": "2"
  }
}</pre>
            </div>

            <div class="pt-2 flex justify-end">
                <button id="cancel-import"
                        class="mr-2 bg-gray-200 hover:bg-gray-300 text-gray-700 px-4 py-2 rounded-lg transition-colors">
                    取消
                </button>
                <button id="confirm-import"
                        class="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-lg transition-colors"
                        disabled>
                    <i class="fa fa-check mr-1"></i>确认导入
                </button>
            </div>
        </div>
    </div>
</div>

<!-- 编辑座位弹窗 -->
<div id="seat-modal" class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center hidden">
    <div class="bg-white rounded-xl shadow-lg w-full max-w-md p-6 transform transition-all">
        <div class="flex justify-between items-center mb-4">
            <h3 class="text-lg font-bold text-dark">编辑座位信息</h3>
            <button id="close-seat" class="text-gray-500 hover:text-gray-700">
                <i class="fa fa-times"></i>
            </button>
        </div>

        <input type="hidden" id="seat-id">
        <input type="hidden" id="seat-position">

        <div class="space-y-4">
            <div>
                <label class="block text-sm font-medium text-gray-700 mb-1">座位位置</label>
                <p id="position-display"
                   class="text-gray-500 text-sm p-2 border border-gray-200 rounded-md bg-gray-50"></p>
            </div>

            <div>
                <label for="student-id" class="block text-sm font-medium text-gray-700 mb-1">学号</label>
                <input type="text" id="student-id" class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm"
                       placeholder="例如：2023001001">
            </div>

            <div>
                <label for="student-name" class="block text-sm font-medium text-gray-700 mb-1">姓名</label>
                <input type="text" id="student-name" class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm">
            </div>

            <div>
                <label for="student-phone" class="block text-sm font-medium text-gray-700 mb-1">手机号码</label>
                <input type="tel" id="student-phone" class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm"
                       placeholder="11位手机号码">
            </div>

            <div>
                <label for="student-class" class="block text-sm font-medium text-gray-700 mb-1">班级</label>
                <select id="student-class" class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm">
                    <option value="0">未分配</option>
                    <!-- 班级选项将通过JS生成 -->
                </select>
            </div>

            <div class="pt-2 flex space-x-2">
                <button id="delete-seat"
                        class="flex-1 bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 rounded-lg transition-colors">
                    <i class="fa fa-trash mr-1"></i>清空
                </button>
                <button id="save-seat"
                        class="flex-1 bg-primary hover:bg-primary/90 text-white py-2 rounded-lg transition-colors">
                    保存信息
                </button>
            </div>
        </div>
    </div>
</div>

<!-- 重置确认弹窗 -->
<div id="reset-modal" class="fixed inset-0 bg-black/50 z-50 flex items-center justify-center hidden">
    <div class="bg-white rounded-xl shadow-lg w-full max-w-md p-6 transform transition-all">
        <div class="text-center mb-4">
            <div class="inline-flex items-center justify-center w-12 h-12 rounded-full bg-red-100 text-red-500 mb-4">
                <i class="fa fa-exclamation-triangle text-xl"></i>
            </div>
            <h3 class="text-lg font-bold text-dark">确认重置</h3>
            <p class="text-neutral mt-2">确定要重置所有座位信息和配置吗？此操作不可撤销，所有本地保存的数据将被清除。</p>
        </div>

        <div class="pt-2 flex space-x-2">
            <button id="cancel-reset"
                    class="flex-1 bg-gray-200 hover:bg-gray-300 text-gray-700 py-2 rounded-lg transition-colors">
                取消
            </button>
            <button id="confirm-reset"
                    class="flex-1 bg-red-500 hover:bg-red-600 text-white py-2 rounded-lg transition-colors">
                确认重置
            </button>
        </div>
    </div>
</div>

<!-- 通知提示 -->
<div id="notification" class="notification bg-green-500 text-white">
    <i class="fa fa-check-circle mr-2"></i>
    <span id="notification-text">操作成功</span>
</div>

<!-- JavaScript 代码 -->
<script>
    // 后端模式：不再使用 Firebase

    // 座位配置
    let seatConfig = {
        left: {columns: 4, rows: 9},
        middle: {columns: 6, rows: 10},
        right: {columns: 4, rows: 6}
    };

    // 班级数据（从后端加载，初始为空）
    let classesData = [];

    // 存储座位数据 - 初始为空
    let seatData = {};

    // 从后端加载数据
    async function loadFromBackend() {
        try {
            // 获取或创建默认教室
            const rooms = await apiGet(API.classrooms).catch(() => []);
            if (Array.isArray(rooms) && rooms.length > 0) {
                CURRENT_CLASSROOM_ID = rooms[0].id;
            } else {
                const newId = await apiJson(API.classrooms, 'POST', {
                    roomCode: `DEFAULT-${Date.now()}`,
                    roomName: '默认教室'
                });
                CURRENT_CLASSROOM_ID = newId;
            }

            const [config, classes, seats] = await Promise.all([
                apiGet(API.seatConfigActive(CURRENT_CLASSROOM_ID)).catch(() => null),
                apiGet(API.classes).catch(() => []),
                apiGet(API.seatsByClassroom(CURRENT_CLASSROOM_ID)).catch(() => [])
            ]);

            if (config) {
                seatConfig = {
                    left: {columns: config.leftColumns, rows: config.leftRows},
                    middle: {columns: config.middleColumns, rows: config.middleRows},
                    right: {columns: config.rightColumns, rows: config.rightRows}
                };
            }

            if (Array.isArray(classes) && classes.length > 0) {
                classesData = classes.map(c => ({id: String(c.id), name: c.className, color: c.colorHex || '#4F46E5'}));
            }

            if (Array.isArray(seats) && seats.length > 0) {
                seatData = {};
                seats.forEach(s => {
                    const seatId = `${s.section}-${s.columnIndex}-${s.rowIndex}`;
                    seatData[seatId] = {
                        id: s.studentNo || '',
                        name: s.studentName || '',
                        phone: s.phone || '',
                        class: s.classId ? String(s.classId) : '0'
                    };
                });
            } else {
                initializeEmptySeats();
            }

            showNotification('数据已从服务器加载');
        } catch (e) {
            console.error('加载后端数据失败:', e);
            showNotification('加载服务器数据失败，使用默认配置', 'error');
            resetToDefault();
        }
    }

    // 初始化空座位
    function initializeEmptySeats() {
        seatData = {};

        // 计算起始列索引
        const leftCols = seatConfig.left.columns;
        const middleCols = seatConfig.middle.columns;

        // 自适应座位尺寸，撑满容器且不产生水平滚动
        autoFitSeatSize();

        // 确保走道在初始渲染时可见：根据最大行数设置父容器最小高度
        const maxRows = Math.max(seatConfig.left.rows, seatConfig.middle.rows, seatConfig.right.rows);
        const seatingRoot = document.getElementById('seating-container');
        if (seatingRoot) {
            seatingRoot.style.alignItems = 'stretch';
            const minH = `calc(${maxRows} * var(--seat-size) + ${(maxRows - 1) * 8}px)`;
            seatingRoot.style.minHeight = minH;
        }

        // 初始化左侧区域空座位
        for (let col = 1; col <= leftCols; col++) {
            for (let row = 1; row <= seatConfig.left.rows; row++) {
                const seatId = `left-${col}-${row}`;
                seatData[seatId] = {
                    id: '',
                    name: '',
                    phone: '',
                    class: '0'
                };
            }
        }

        // 初始化中间区域空座位
        for (let col = 1; col <= middleCols; col++) {
            const actualCol = leftCols + col;
            for (let row = 1; row <= seatConfig.middle.rows; row++) {
                const seatId = `middle-${actualCol}-${row}`;
                seatData[seatId] = {
                    id: '',
                    name: '',
                    phone: '',
                    class: '0'
                };
            }
        }

        // 初始化右侧区域空座位
        const rightStartCol = leftCols + middleCols + 1;
        for (let col = 1; col <= seatConfig.right.columns; col++) {
            const actualCol = rightStartCol + (col - 1);
            for (let row = 1; row <= seatConfig.right.rows; row++) {
                const seatId = `right-${actualCol}-${row}`;
                seatData[seatId] = {
                    id: '',
                    name: '',
                    phone: '',
                    class: '0'
                };
            }
        }

        // 保存空座位数据
        saveToLocalStorage();
    }

    // 根据容器宽度自适应 seat 大小，避免水平滚动
    function autoFitSeatSize() {
        const container = document.getElementById('seating-container');
        if (!container) return;
        const totalColumns = seatConfig.left.columns + seatConfig.middle.columns + seatConfig.right.columns;
        const styles = getComputedStyle(container);
        const paddingLeft = parseInt(styles.paddingLeft || '0');
        const paddingRight = parseInt(styles.paddingRight || '0');
        const gap = 8; // grid gap
        const aisles = 2; // two aisles
        const aisleWidth = 12; // match .aisle default
        const available = container.clientWidth - paddingLeft - paddingRight - (totalColumns - 1) * gap - aisles * aisleWidth;
        const seatSize = Math.max(64, Math.floor(available / totalColumns));
        document.documentElement.style.setProperty('--seat-size', seatSize + 'px');
    }

    // 兼容函数名：现在不做统一批量保存，具体操作处分别调用后端
    function saveToLocalStorage() {
        return Promise.resolve(true);
    }

    // 添加一个立即执行的函数来处理初始化异步函数的兼容性
    (function () {
        // 检查是否有未完成的异步保存操作
        let pendingSave = false;

        // 重写所有调用saveToLocalStorage的核心函数，确保它们能处理异步操作
        const originalInitSeatingChart = initSeatingChart;
        window.initSeatingChart = function () {
            originalInitSeatingChart();
        };

        // 确保applyConfig等函数在调用saveToLocalStorage后能正确更新UI
        const originalApplyConfig = applyConfig;
        window.applyConfig = function () {
            originalApplyConfig();
        };
    })();

    // 重置为默认配置
    function resetToDefault() {
        seatConfig = {
            left: {columns: 4, rows: 9},
            middle: {columns: 6, rows: 10},
            right: {columns: 4, rows: 6}
        };

        classesData = [
            {id: '1', name: '一班', color: '#4F46E5'},
            {id: '2', name: '二班', color: '#10B981'},
            {id: '3', name: '三班', color: '#F59E0B'},
            {id: '4', name: '四班', color: '#EF4444'}
        ];

        // 重置为空座位
        initializeEmptySeats();
    }

    // 仅清空座位信息，保留配置
    function clearSeatInformation() {
        // 遍历所有座位ID，清空信息
        Object.keys(seatData).forEach(seatId => {
            seatData[seatId] = {
                id: '',
                name: '',
                phone: '',
                class: '0'
            };
        });

        // 保存并更新界面
        if (saveToLocalStorage()) {
            initSeatingChart();
            showNotification('所有座位信息已清空');
        }
    }

    // 清空所有数据
    function clearAllData() {
        resetToDefault();
        updateClassLegend();
        updateClassSelectOptions();
        initSeatingChart();
        showNotification('所有数据已重置为默认值');
    }

    // 显示通知
    function showNotification(message, type = 'success') {
        const notification = document.getElementById('notification');
        const textElement = document.getElementById('notification-text');

        // 设置通知类型样式
        notification.className = 'notification';
        if (type === 'success') {
            notification.classList.add('bg-green-500', 'text-white');
        } else if (type === 'error') {
            notification.classList.add('bg-red-500', 'text-white');
        } else if (type === 'info') {
            notification.classList.add('bg-blue-500', 'text-white');
        } else if (type === 'warning') {
            notification.classList.add('bg-yellow-500', 'text-white');
        }

        // 设置消息
        textElement.textContent = message;

        // 显示通知
        notification.classList.add('show');

        // 3秒后隐藏
        setTimeout(() => {
            notification.classList.remove('show');
        }, 3000);
    }

    // 生成随机姓名
    function generateName() {
        const familyNames = ['张', '王', '李', '赵', '刘', '陈', '杨', '黄', '周', '吴', '徐', '孙', '胡', '朱', '高'];
        const givenNames = ['伟', '芳', '娜', '秀英', '敏', '静', '强', '磊', '军', '洋', '勇', '艳', '杰', '涛', '明'];

        const familyName = familyNames[Math.floor(Math.random() * familyNames.length)];
        const givenName = givenNames[Math.floor(Math.random() * givenNames.length)];

        return familyName + givenName;
    }

    // 生成随机手机号
    function generatePhone() {
        const prefixes = ['130', '131', '132', '133', '134', '135', '136', '137', '138', '139', '150', '151', '152', '153', '155', '156', '157', '158', '159', '170', '176', '177', '178', '180', '181', '182', '183', '184', '185', '186', '187', '188', '189'];
        const prefix = prefixes[Math.floor(Math.random() * prefixes.length)];
        const suffix = Math.floor(Math.random() * 100000000).toString().padStart(8, '0');
        return prefix + suffix;
    }

    // 生成随机学号
    function generateStudentId() {
        const year = '2023';
        const department = Math.floor(Math.random() * 100).toString().padStart(2, '0');
        const number = Math.floor(Math.random() * 1000).toString().padStart(3, '0');
        return year + department + number;
    }

    // 格式化手机号显示 (138 **** 5678)
    function formatPhone(phone) {
        if (!phone || phone.length !== 11) return '';
        return phone.substring(0, 3) + ' **** ' + phone.substring(7);
    }

    // 获取班级信息
    function getClassById(classId) {
        return classesData.find(cls => cls.id === classId) || null;
    }

    // 更新班级图例
    function updateClassLegend() {
        const legendContainer = document.getElementById('class-legend');
        legendContainer.innerHTML = '';

        classesData.forEach(cls => {
            const item = document.createElement('div');
            item.className = 'flex items-center';
            item.innerHTML = `
          <span class="class-badge" style="background-color: ${cls.color}"></span>
          <span>${cls.name}</span>
        `;
            legendContainer.appendChild(item);
        });
    }

    // 更新班级选择下拉框
    function updateClassSelectOptions() {
        const selectElement = document.getElementById('student-class');
        // 保存当前选中值
        const currentValue = selectElement.value;

        // 清除现有选项（保留"未分配"）
        while (selectElement.options.length > 1) {
            selectElement.remove(1);
        }

        // 添加班级选项
        classesData.forEach(cls => {
            const option = document.createElement('option');
            option.value = cls.id;
            option.textContent = cls.name;
            selectElement.appendChild(option);
        });

        // 恢复选中值
        if (currentValue) {
            selectElement.value = currentValue;
        }
    }

    // 渲染班级配置项
    function renderClassConfigItems() {
        const container = document.getElementById('classes-container');
        container.innerHTML = '';

        classesData.forEach((cls, index) => {
            const item = document.createElement('div');
            item.className = 'bg-gray-50 p-4 rounded-lg border border-gray-200';
            item.innerHTML = `
          <div class="flex justify-between items-start mb-3">
            <div class="font-medium">班级 #${parseInt(cls.id)}</div>
            <button class="delete-class text-red-500 hover:text-red-700" data-id="${cls.id}">
              <i class="fa fa-trash"></i>
            </button>
          </div>
          <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
            <div class="md:col-span-2">
              <label class="block text-sm font-medium text-gray-700 mb-1">班级名称</label>
              <input type="text" class="class-name w-full border border-gray-300 rounded-md px-3 py-2 text-sm" 
                     value="${cls.name}" data-id="${cls.id}">
            </div>
            <div>
              <label class="block text-sm font-medium text-gray-700 mb-1">班级颜色</label>
              <div class="flex items-center">
                <input type="color" class="class-color w-8 h-8 p-0 border-0 rounded-md" 
                       value="${cls.color}" data-id="${cls.id}">
                <span class="ml-2 text-sm text-gray-500">${cls.color}</span>
              </div>
            </div>
          </div>
        `;
            container.appendChild(item);
        });

        // 绑定删除班级事件
        document.querySelectorAll('.delete-class').forEach(btn => {
            btn.addEventListener('click', (e) => {
                const classId = e.currentTarget.getAttribute('data-id');
                deleteClass(classId);
            });
        });

        // 绑定班级名称修改事件
        document.querySelectorAll('.class-name').forEach(input => {
            input.addEventListener('change', (e) => {
                const classId = e.currentTarget.getAttribute('data-id');
                const newName = e.currentTarget.value.trim();
                if (newName) {
                    updateClassName(classId, newName);
                }
            });
        });

        // 绑定班级颜色修改事件
        document.querySelectorAll('.class-color').forEach(input => {
            input.addEventListener('input', (e) => {
                const classId = e.currentTarget.getAttribute('data-id');
                const newColor = e.currentTarget.value;
                updateClassColor(classId, newColor);
            });
        });
    }

    // 添加新班级
    function addNewClass() {
        const defaultColors = ['#8B5CF6', '#EC4899', '#06B6D4', '#6366F1'];
        const randomColor = defaultColors[Math.floor(Math.random() * defaultColors.length)];
        const name = `新班级`;
        const classCode = `C${Date.now()}`;
        apiJson(API.classes, 'POST', {
            classCode: classCode,
            className: name,
            colorHex: randomColor
        }).then((id) => {
            classesData.push({id: String(id), name, color: randomColor});
            renderClassConfigItems();
            updateClassLegend();
            updateClassSelectOptions();
            initSeatingChart();
            showNotification('已添加新班级');
        }).catch(e => {
            console.error(e);
            showNotification('添加班级失败', 'error');
        });
    }

    // 删除班级
    function deleteClass(classId) {
        // 不能删除最后一个班级
        if (classesData.length <= 1) {
            showNotification('至少保留一个班级', 'error');
            return;
        }

        // 将属于该班级的学生设为未分配
        Object.keys(seatData).forEach(seatId => {
            if (seatData[seatId].class === classId) {
                seatData[seatId].class = '0';
            }
        });

        apiJson(`${API.classes}/${classId}`, 'DELETE').then(() => {
        classesData = classesData.filter(cls => cls.id !== classId);
            renderClassConfigItems();
            updateClassLegend();
            updateClassSelectOptions();
            initSeatingChart();
            showNotification('班级已删除');
        }).catch(e => {
            console.error(e);
            showNotification('删除班级失败', 'error');
        });
    }

    // 更新班级名称
    function updateClassName(classId, newName) {
        const cls = getClassById(classId);
        if (cls) {
            apiJson(`${API.classes}/${classId}`, 'PUT', {id: Number(classId), className: newName, colorHex: cls.color})
                .then(() => {
            cls.name = newName;
                updateClassLegend();
                updateClassSelectOptions();
                initSeatingChart();
                showNotification(`班级名称已更新为${newName}`);
                }).catch(e => {
                console.error(e);
                showNotification('更新班级名称失败', 'error');
            });
        }
    }

    // 更新班级颜色
    function updateClassColor(classId, newColor) {
        const cls = getClassById(classId);
        if (cls) {
            apiJson(`${API.classes}/${classId}`, 'PUT', {id: Number(classId), className: cls.name, colorHex: newColor})
                .then(() => {
            cls.color = newColor;
                updateClassLegend();
                initSeatingChart();
                showNotification('班级颜色已更新');
                }).catch(e => {
                console.error(e);
                showNotification('更新班级颜色失败', 'error');
            });
        }
    }

    // 恢复默认班级设置
    function resetClassesToDefault() {
        apiGet(API.classes).then(list => {
            const deletes = (list || []).map(c => apiJson(`${API.classes}/${c.id}`, 'DELETE'));
            return Promise.allSettled(deletes);
        }).then(() => {
            const defaults = [
                {name: '一班', color: '#4F46E5'},
                {name: '二班', color: '#10B981'},
                {name: '三班', color: '#F59E0B'},
                {name: '四班', color: '#EF4444'}
            ];
            return Promise.all(defaults.map(d => apiJson(API.classes, 'POST', {
                classCode: `C${Date.now()}${Math.floor(Math.random() * 1000)}`,
                className: d.name,
                colorHex: d.color
            })));
        }).then((ids) => {
            classesData = ids.map((id, idx) => ({
                id: String(id),
                name: ['一班', '二班', '三班', '四班'][idx],
                color: ['#4F46E5', '#10B981', '#F59E0B', '#EF4444'][idx]
            }));
            renderClassConfigItems();
            updateClassLegend();
            updateClassSelectOptions();
            initSeatingChart();
            showNotification('班级设置已恢复默认');
        }).catch(e => {
            console.error(e);
            showNotification('恢复默认班级失败', 'error');
        });
    }

    // 创建座位元素
    function createSeat(section, column, row) {
        const seatId = `${section}-${column}-${row}`;
        // 确保座位数据存在，若不存在则初始化为空
        if (!seatData[seatId]) {
            seatData[seatId] = {
                id: '',
                name: '',
                phone: '',
                class: '0'
            };
        }

        const data = seatData[seatId];
        const position = `${column}列-${row}行`;
        const cls = getClassById(data.class);
        const classStyle = cls ? `border border-[${cls.color}] bg-[${cls.color}]10` : 'border-gray-300 bg-gray-50';

        const seat = document.createElement('div');
        seat.className = `seat-hover seat-tile rounded-lg p-2 mb-2 relative cursor-pointer ${classStyle}`;

        seat.innerHTML = `
        <div class="text-xs text-neutral mb-1">${position}</div>
        <div class="text-xs text-neutral/80 truncate mb-1">${data.id || ''}</div>
        <div class="font-medium text-sm truncate ${data.name ? '' : 'text-gray-400 italic'}">${data.name || '未分配'}</div>
        <div class="text-xs text-neutral/80 mt-1 truncate">${formatPhone(data.phone)}</div>
        ${cls ? `<div class="absolute top-1 right-1 class-badge" style="background-color: ${cls.color}"></div>` : ''}
      `;

        // 添加点击事件，打开编辑弹窗
        seat.addEventListener('click', () => {
            openSeatEditModal(seatId, position, data);
        });

        return seat;
    }

    // 生成座位区域
    function generateSeatingSection(containerId, sectionName, columns, startColumnIndex, rows) {
        const container = document.getElementById(containerId);
        container.innerHTML = '';
        // 使用 CSS Grid，按列数均分并自动行高，避免水平滚动
        container.style.display = 'grid';
        container.style.gridTemplateColumns = `repeat(${columns}, minmax(64px, var(--seat-size)))`;
        container.style.gridAutoRows = 'var(--seat-size)';
        container.style.gridColumnGap = '8px';
        container.style.gridRowGap = '8px';

        for (let col = 0; col < columns; col++) {
            const columnNumber = startColumnIndex + col;
            for (let row = 1; row <= rows; row++) {
                const seat = createSeat(sectionName, columnNumber, row);
                container.appendChild(seat);

                const seatId = `${sectionName}-${columnNumber}-${row}`;
                if (!seatData[seatId]) {
                    seatData[seatId] = {id: '', name: '', phone: '', class: '0'};
                }
            }
        }
    }

    // 初始化座位表
    function initSeatingChart() {
        // 计算起始列索引
        const leftCols = seatConfig.left.columns;
        const middleCols = seatConfig.middle.columns;

        // 生成左侧区域
        generateSeatingSection('left-section', 'left', leftCols, 1, seatConfig.left.rows);

        // 生成中间区域
        generateSeatingSection('middle-section', 'middle', middleCols, leftCols + 1, seatConfig.middle.rows);

        // 生成右侧区域
        generateSeatingSection('right-section', 'right', seatConfig.right.columns, leftCols + middleCols + 1, seatConfig.right.rows);

        // 确保所有座位都有数据记录
        ensureAllSeatsExist();

        // 更新总人数
        updateTotalCount();
    }

    // 确保所有座位都有数据记录
    function ensureAllSeatsExist() {
        let updated = false;

        // 计算起始列索引
        const leftCols = seatConfig.left.columns;
        const middleCols = seatConfig.middle.columns;

        // 检查左侧区域
        for (let col = 1; col <= leftCols; col++) {
            for (let row = 1; row <= seatConfig.left.rows; row++) {
                const seatId = `left-${col}-${row}`;
                if (!seatData[seatId]) {
                    seatData[seatId] = {
                        id: '',
                        name: '',
                        phone: '',
                        class: '0'
                    };
                    updated = true;
                }
            }
        }

        // 检查中间区域
        for (let col = 1; col <= middleCols; col++) {
            const actualCol = leftCols + col;
            for (let row = 1; row <= seatConfig.middle.rows; row++) {
                const seatId = `middle-${actualCol}-${row}`;
                if (!seatData[seatId]) {
                    seatData[seatId] = {
                        id: '',
                        name: '',
                        phone: '',
                        class: '0'
                    };
                    updated = true;
                }
            }
        }

        // 检查右侧区域
        const rightStartCol = leftCols + middleCols + 1;
        for (let col = 1; col <= seatConfig.right.columns; col++) {
            const actualCol = rightStartCol + (col - 1);
            for (let row = 1; row <= seatConfig.right.rows; row++) {
                const seatId = `right-${actualCol}-${row}`;
                if (!seatData[seatId]) {
                    seatData[seatId] = {
                        id: '',
                        name: '',
                        phone: '',
                        class: '0'
                    };
                    updated = true;
                }
            }
        }

        // 如果有更新，保存数据
        if (updated) {
            saveToLocalStorage();
        }
    }

    // 更新总人数统计
    function updateTotalCount() {
        let count = 0;
        Object.values(seatData).forEach(data => {
            if (data.name) count++;
        });
        document.getElementById('total-count').textContent = `总人数: ${count}`;
    }

    // 打开配置弹窗
    function openConfigModal() {
        document.getElementById('left-columns').value = seatConfig.left.columns;
        document.getElementById('left-rows').value = seatConfig.left.rows;
        document.getElementById('middle-columns').value = seatConfig.middle.columns;
        document.getElementById('middle-rows').value = seatConfig.middle.rows;
        document.getElementById('right-columns').value = seatConfig.right.columns;
        document.getElementById('right-rows').value = seatConfig.right.rows;

        document.getElementById('config-modal').classList.remove('hidden');
    }

    // 关闭配置弹窗
    function closeConfigModal() {
        document.getElementById('config-modal').classList.add('hidden');
    }

    // 应用配置
    function applyConfig() {
        // 验证并更新配置
        const newConfig = {
            left: {
                columns: Math.min(10, Math.max(1, parseInt(document.getElementById('left-columns').value) || 1)),
                rows: Math.min(20, Math.max(1, parseInt(document.getElementById('left-rows').value) || 1))
            },
            middle: {
                columns: Math.min(10, Math.max(1, parseInt(document.getElementById('middle-columns').value) || 1)),
                rows: Math.min(20, Math.max(1, parseInt(document.getElementById('middle-rows').value) || 1))
            },
            right: {
                columns: Math.min(10, Math.max(1, parseInt(document.getElementById('right-columns').value) || 1)),
                rows: Math.min(20, Math.max(1, parseInt(document.getElementById('right-rows').value) || 1))
            }
        };

        // 检查配置是否有变化
        const configChanged = JSON.stringify(newConfig) !== JSON.stringify(seatConfig);

        if (configChanged) {
            seatConfig = newConfig;
            // 保存到后端并同步空座位
            apiJson(API.seatConfig, 'POST', {
                classroomId: CURRENT_CLASSROOM_ID,
                leftColumns: seatConfig.left.columns,
                leftRows: seatConfig.left.rows,
                middleColumns: seatConfig.middle.columns,
                middleRows: seatConfig.middle.rows,
                rightColumns: seatConfig.right.columns,
                rightRows: seatConfig.right.rows,
                isActive: 1
            }).then(() => {
                initializeEmptySeats();
                return syncEmptySeatsToBackend();
            }).then(() => {
                initSeatingChart();
                showNotification('座位配置已更新并保存');
            }).catch(e => {
                console.error(e);
                showNotification('保存座位配置失败', 'error');
            });
        } else {
            showNotification('配置未发生变化', 'info');
        }

        // 关闭弹窗
        closeConfigModal();
    }

    // 打开班级配置弹窗
    function openClassConfigModal() {
        renderClassConfigItems();
        document.getElementById('class-config-modal').classList.remove('hidden');
    }

    // 关闭班级配置弹窗
    function closeClassConfigModal() {
        document.getElementById('class-config-modal').classList.add('hidden');
    }

    // 打开导入弹窗
    function openImportModal() {
        // 重置文件输入
        document.getElementById('import-file').value = '';
        document.getElementById('confirm-import').disabled = true;
        document.getElementById('overwrite-existing').checked = false;
        document.getElementById('import-by-position').checked = true;

        document.getElementById('import-modal').classList.remove('hidden');
    }

    // 关闭导入弹窗
    function closeImportModal() {
        document.getElementById('import-modal').classList.add('hidden');
    }

    // 处理文件选择
    function handleFileSelection(event) {
        const fileInput = event.target;
        const confirmBtn = document.getElementById('confirm-import');

        if (fileInput.files && fileInput.files.length > 0) {
            const file = fileInput.files[0];
            // 检查文件类型
            if (file.type === 'application/json' || file.name.endsWith('.json')) {
                confirmBtn.disabled = false;
                showNotification(`已选择文件: ${file.name}`, 'info');
            } else {
                confirmBtn.disabled = true;
                showNotification('请选择JSON格式的文件', 'error');
                fileInput.value = '';
            }
        } else {
            confirmBtn.disabled = true;
        }
    }

    // 处理文件拖放
    function handleDragOver(event) {
        event.preventDefault();
        document.getElementById('file-drop-area').classList.add('border-primary', 'bg-blue-50');
    }

    function handleDragLeave(event) {
        document.getElementById('file-drop-area').classList.remove('border-primary', 'bg-blue-50');
    }

    function handleDrop(event) {
        event.preventDefault();
        document.getElementById('file-drop-area').classList.remove('border-primary', 'bg-blue-50');

        const fileInput = document.getElementById('import-file');
        const confirmBtn = document.getElementById('confirm-import');

        if (event.dataTransfer.files && event.dataTransfer.files.length > 0) {
            const file = event.dataTransfer.files[0];
            // 检查文件类型
            if (file.type === 'application/json' || file.name.endsWith('.json')) {
                // 将拖放的文件赋值给文件输入
                fileInput.files = event.dataTransfer.files;
                confirmBtn.disabled = false;
                showNotification(`已选择文件: ${file.name}`, 'info');
            } else {
                confirmBtn.disabled = true;
                showNotification('请选择JSON格式的文件', 'error');
            }
        } else {
            confirmBtn.disabled = true;
        }
    }

    // 执行导入
    function performImport() {
        const fileInput = document.getElementById('import-file');
        const importMethod = document.querySelector('input[name="import-method"]:checked').value;
        const overwriteExisting = document.getElementById('overwrite-existing').checked;

        if (!fileInput.files || fileInput.files.length === 0) {
            showNotification('请选择要导入的文件', 'error');
            return;
        }

        const file = fileInput.files[0];
        const reader = new FileReader();

        reader.onload = function (e) {
            try {
                const importData = JSON.parse(e.target.result);
                let importedCount = 0;

                if (importMethod === 'position') {
                    // 按位置导入
                    Object.keys(importData).forEach(position => {
                        // 位置格式: "X列-Y行"
                        const match = position.match(/^(\d+)列-(\d+)行$/);
                        if (match) {
                            const column = parseInt(match[1]);
                            const row = parseInt(match[2]);

                            // 查找对应的座位ID
                            const seatId = findSeatIdByPosition(column, row);
                            if (seatId) {
                                // 检查是否需要覆盖
                                if (overwriteExisting || !seatData[seatId].name) {
                                    // 验证导入数据
                                    if (importData[position].name) {
                                        seatData[seatId] = {
                                            id: importData[position].id || '',
                                            name: importData[position].name || '',
                                            phone: importData[position].phone || '',
                                            class: importData[position].class || '0'
                                        };
                                        importedCount++;
                                    }
                                }
                            }
                        }
                    });
                } else {
                    // 自动分配
                    const emptySeats = getEmptySeats();
                    const importEntries = Object.values(importData);

                    // 按顺序填充空座位
                    for (let i = 0; i < Math.min(emptySeats.length, importEntries.length); i++) {
                        const seatId = emptySeats[i];
                        const studentData = importEntries[i];

                        if (studentData.name) {
                            seatData[seatId] = {
                                id: studentData.id || '',
                                name: studentData.name || '',
                                phone: studentData.phone || '',
                                class: studentData.class || '0'
                            };
                            importedCount++;
                        }
                    }
                }

                // 同步到后端（逐条 upsert）
                const upserts = [];
                Object.keys(seatData).forEach(key => {
                    const d = seatData[key];
                    if (!d) return;
                    const parts = key.split('-');
                    const section = parts[0];
                    const columnIndex = parseInt(parts[1]);
                    const rowIndex = parseInt(parts[2]);
                    upserts.push(apiJson(API.seats, 'POST', {
                        classroomId: CURRENT_CLASSROOM_ID,
                        section,
                        columnIndex,
                        rowIndex,
                        studentNo: d.id || '',
                        studentName: d.name || '',
                        phone: d.phone || '',
                        classId: d.class && d.class !== '0' ? Number(d.class) : null
                    }));
                });

                Promise.allSettled(upserts).then(() => {
                    initSeatingChart();
                    closeImportModal();
                    showNotification(`成功导入 ${importedCount} 条记录`);
                }).catch(e => {
                    console.error(e);
                    showNotification('导入后端同步失败', 'error');
                });
            } catch (error) {
                console.error('导入失败:', error);
                showNotification('导入失败，文件格式不正确', 'error');
            }
        };

        reader.onerror = function () {
            showNotification('读取文件失败', 'error');
        };

        reader.readAsText(file);
    }

    // 根据位置查找座位ID
    function findSeatIdByPosition(column, row) {
        // 计算区域
        const leftCols = seatConfig.left.columns;
        const middleCols = seatConfig.middle.columns;
        const rightStartCol = leftCols + middleCols + 1;

        let section;

        if (column <= leftCols) {
            section = 'left';
        } else if (column <= leftCols + middleCols) {
            section = 'middle';
        } else if (column >= rightStartCol) {
            section = 'right';
        } else {
            return null; // 不在任何区域
        }

        // 检查行是否在有效范围内
        let rowValid = false;
        if (section === 'left' && row <= seatConfig.left.rows) rowValid = true;
        if (section === 'middle' && row <= seatConfig.middle.rows) rowValid = true;
        if (section === 'right' && row <= seatConfig.right.rows) rowValid = true;

        if (!rowValid) return null;

        return `${section}-${column}-${row}`;
    }

    // 获取所有空座位
    function getEmptySeats() {
        return Object.keys(seatData).filter(seatId => {
            return !seatData[seatId].name; // 姓名为空视为空座位
        });
    }

    // 打开座位编辑弹窗
    function openSeatEditModal(seatId, position, data) {
        document.getElementById('seat-id').value = seatId;
        document.getElementById('seat-position').value = position;
        document.getElementById('position-display').textContent = position;
        document.getElementById('student-id').value = data.id || '';
        document.getElementById('student-name').value = data.name || '';
        document.getElementById('student-phone').value = data.phone || '';
        document.getElementById('student-class').value = data.class || '0';

        document.getElementById('seat-modal').classList.remove('hidden');
    }

    // 关闭座位编辑弹窗
    function closeSeatEditModal() {
        document.getElementById('seat-modal').classList.add('hidden');
    }

    // 保存座位信息
    function saveSeatInfo() {
        const seatId = document.getElementById('seat-id').value;
        const studentId = document.getElementById('student-id').value.trim();
        const name = document.getElementById('student-name').value.trim();
        const phone = document.getElementById('student-phone').value.trim();
        const classId = document.getElementById('student-class').value;

        // 验证手机号
        if (phone && !/^1[3-9]\d{9}$/.test(phone)) {
            alert('请输入有效的11位手机号码');
            return;
        }

        // 本地更新
        seatData[seatId] = {id: studentId, name, phone, class: classId};

        const parts = seatId.split('-');
        const section = parts[0];
        const columnIndex = parseInt(parts[1]);
        const rowIndex = parseInt(parts[2]);

        apiJson(API.seats, 'POST', {
            classroomId: CURRENT_CLASSROOM_ID,
            section,
            columnIndex,
            rowIndex,
            studentNo: studentId,
            studentName: name,
            phone: phone,
            classId: classId === '0' ? null : Number(classId)
        }).then(() => {
            initSeatingChart();
            showNotification('座位信息已保存');
        }).catch(e => {
            console.error(e);
            showNotification('保存座位信息失败', 'error');
        }).finally(() => closeSeatEditModal());
    }

    // 清空座位信息
    function clearSeatInfo() {
        const seatId = document.getElementById('seat-id').value;

        // 清空数据
        seatData[seatId] = {
            id: '',
            name: '',
            phone: '',
            class: '0'
        };

        const parts = seatId.split('-');
        const section = parts[0];
        const columnIndex = parseInt(parts[1]);
        const rowIndex = parseInt(parts[2]);

        apiJson(API.seats, 'POST', {
            classroomId: CURRENT_CLASSROOM_ID,
            section,
            columnIndex,
            rowIndex,
            studentNo: '',
            studentName: '',
            phone: '',
            classId: null
        }).then(() => {
            initSeatingChart();
            showNotification('座位信息已清空');
        }).catch(e => {
            console.error(e);
            showNotification('清空座位信息失败', 'error');
        }).finally(() => closeSeatEditModal());
    }

    // 导出座位表
    function exportSeatingChart() {
        // 准备导出数据
        const exportData = {};

        // 整理座位数据，按位置存储
        Object.keys(seatData).forEach(key => {
            const parts = key.split('-');
            if (parts.length === 3) {
                const [section, column, row] = parts;
                const position = `${column}列-${row}行`;
                exportData[position] = seatData[key];
            }
        });

        // 创建JSON字符串
        const jsonStr = JSON.stringify(exportData, null, 2);
        const blob = new Blob([jsonStr], {type: 'application/json'});
        const url = URL.createObjectURL(blob);

        // 创建下载链接
        const a = document.createElement('a');
        a.href = url;
        a.download = `教室座位表_${new Date().toLocaleDateString().replace(/\//g, '-')}.json`;
        document.body.appendChild(a);
        a.click();

        // 清理
        setTimeout(() => {
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
        }, 0);

        showNotification('座位表已导出为JSON文件');
    }

    // 打开重置确认弹窗
    function openResetModal() {
        document.getElementById('reset-modal').classList.remove('hidden');
    }

    // 关闭重置确认弹窗
    function closeResetModal() {
        document.getElementById('reset-modal').classList.add('hidden');
    }

    // 绑定事件
    function bindEvents() {
        // 配置弹窗
        document.getElementById('config-btn').addEventListener('click', openConfigModal);
        document.getElementById('close-config').addEventListener('click', closeConfigModal);
        document.getElementById('apply-config').addEventListener('click', applyConfig);

        // 班级配置弹窗
        document.getElementById('class-config-btn').addEventListener('click', openClassConfigModal);
        document.getElementById('close-class-config').addEventListener('click', closeClassConfigModal);
        document.getElementById('add-class').addEventListener('click', addNewClass);
        document.getElementById('reset-classes').addEventListener('click', resetClassesToDefault);

        // 已移除导入/导出/重置相关事件

        // 座位编辑弹窗
        document.getElementById('close-seat').addEventListener('click', closeSeatEditModal);
        document.getElementById('save-seat').addEventListener('click', saveSeatInfo);
        document.getElementById('delete-seat').addEventListener('click', clearSeatInfo);


        // 点击弹窗外部关闭弹窗
        document.getElementById('config-modal').addEventListener('click', (e) => {
            if (e.target === document.getElementById('config-modal')) {
                closeConfigModal();
            }
        });

        document.getElementById('class-config-modal').addEventListener('click', (e) => {
            if (e.target === document.getElementById('class-config-modal')) {
                closeClassConfigModal();
            }
        });

        document.getElementById('import-modal').addEventListener('click', (e) => {
            if (e.target === document.getElementById('import-modal')) {
                closeImportModal();
            }
        });

        document.getElementById('seat-modal').addEventListener('click', (e) => {
            if (e.target === document.getElementById('seat-modal')) {
                closeSeatEditModal();
            }
        });

        document.getElementById('reset-modal').addEventListener('click', (e) => {
            if (e.target === document.getElementById('reset-modal')) {
                document.getElementById('reset-modal').classList.add('hidden');
            }
        });

        // 按ESC键关闭弹窗
        document.addEventListener('keydown', (e) => {
            if (e.key === 'Escape') {
                closeConfigModal();
                closeClassConfigModal();
                closeImportModal();
                closeSeatEditModal();
                document.getElementById('reset-modal').classList.add('hidden');
            }
        });
    }

    // 页面加载完成后初始化
    document.addEventListener('DOMContentLoaded', function () {
        // 检查网络连接状态
        function checkNetworkStatus() {
            const offlineNotice = document.getElementById('offline-notice');
            if (!navigator.onLine) {
                offlineNotice.classList.remove('hidden');
                showNotification('当前离线，数据可能无法同步', 'warning');
            } else {
                offlineNotice.classList.add('hidden');
            }
        }

        // 监听网络连接变化
        window.addEventListener('online', checkNetworkStatus);
        window.addEventListener('offline', checkNetworkStatus);

        // 先检查网络状态
        checkNetworkStatus();

        // 从后端加载数据
        loadFromBackend().then(async () => {
            // 更新班级图例和选择框
            updateClassLegend();
            updateClassSelectOptions();
            // 初始化座位表
            initSeatingChart();
            // 绑定事件
            bindEvents();

            // 去除 Firebase 实时监听，前端单机拉取
        });
    });

    // 将空座位写入后端（仅用于初始化或配置变更后）
    function syncEmptySeatsToBackend() {
        const seats = [];
        const leftCols = seatConfig.left.columns;
        const middleCols = seatConfig.middle.columns;
        // 左
        for (let col = 1; col <= leftCols; col++) {
            for (let row = 1; row <= seatConfig.left.rows; row++) {
                seats.push({
                    classroomId: CURRENT_CLASSROOM_ID,
                    section: 'left',
                    columnIndex: col,
                    rowIndex: row,
                    studentNo: '',
                    studentName: '',
                    phone: '',
                    classId: null
                });
            }
        }
        // 中
        for (let col = 1; col <= middleCols; col++) {
            const actualCol = leftCols + col;
            for (let row = 1; row <= seatConfig.middle.rows; row++) {
                seats.push({
                    classroomId: CURRENT_CLASSROOM_ID,
                    section: 'middle',
                    columnIndex: actualCol,
                    rowIndex: row,
                    studentNo: '',
                    studentName: '',
                    phone: '',
                    classId: null
                });
            }
        }
        // 右
        const rightStartCol = leftCols + middleCols + 1;
        for (let col = 1; col <= seatConfig.right.columns; col++) {
            const actualCol = rightStartCol + (col - 1);
            for (let row = 1; row <= seatConfig.right.rows; row++) {
                seats.push({
                    classroomId: CURRENT_CLASSROOM_ID,
                    section: 'right',
                    columnIndex: actualCol,
                    rowIndex: row,
                    studentNo: '',
                    studentName: '',
                    phone: '',
                    classId: null
                });
            }
        }
        if (seats.length > 0) {
            return apiJson(`${API.seats}/init`, 'POST', seats).catch(e => {
                console.error('批量初始化空座位失败', e);
                throw e;
            });
        }
        return Promise.resolve(true);
    }
</script>
</body>
</html>
    